# Purpose: Implements the logic for generating task execution reports.
# Changes:
# - Verified imports and schema usage based on latest corrections.

import logging
import json
from typing import List, Dict, Any, Optional
from pathlib import Path
from datetime import datetime, timezone # Ensure timezone is imported

# Use relative imports
from ...core.exceptions import SkillError
from ...core.config import get_config_value
# Import corrected schemas
from ...schemas.agent import Task, Plan, Step

# Use core logger setup
from ...core.logging_setup import get_logger
logger = get_logger(__name__)


async def generate_report(
    task: Task,
    plan: Optional[Plan] = None,
    output_format: str = "markdown" # Currently only markdown implemented
) -> str:
    """
    Generates a report summarizing the task execution.

    Args:
        task: The final Task object.
        plan: The Plan object used for execution (if available).
        output_format: The desired format ("markdown").

    Returns:
        The generated report content as a string.

    Raises:
        SkillError: If report generation fails.
    """
    skill_name = "generate_report"
    logger.info(f"[{skill_name.upper()}] Generating '{output_format}' report for Task ID: {task.id}")

    report_lines = []
    try:
        # --- Header ---
        report_lines.append(f"# Task Execution Report")
        report_lines.append(f"**Task ID:** `{task.id}`")
        report_lines.append(f"**Goal:** {task.description}")
        report_lines.append(f"**Final Status:** {task.status.upper()}")

        # Format timestamps safely, handling potential None and timezone
        start_time_str = "N/A"
        if task.created_at:
            start_time_local = task.created_at.astimezone() # Convert to local timezone for display
            start_time_str = start_time_local.strftime('%Y-%m-%d %H:%M:%S %Z')
        end_time_str = "N/A"
        if task.updated_at:
            end_time_local = task.updated_at.astimezone()
            end_time_str = end_time_local.strftime('%Y-%m-%d %H:%M:%S %Z')

        report_lines.append(f"**Started:** {start_time_str}")
        report_lines.append(f"**Finished:** {end_time_str}")
        if task.status == "failed":
             # Ensure error message is treated as optional
             report_lines.append(f"**Error:** {task.error_message or 'No error message provided.'}")


        # --- Plan and Execution Summary ---
        report_lines.append(f"\n## Execution Summary")
        # Check plan and steps existence
        if plan and plan.steps:
             report_lines.append(f"_(Plan ID: `{plan.id}`)_")
             report_lines.append("| Step | Tool Called | Status | Outcome Summary |")
             report_lines.append("|------|-------------|--------|-----------------|")
             for step in plan.steps:
                  outcome = ""
                  # Use the status field which has a default in the schema
                  step_status = step.status.upper()

                  if step.status == 'completed':
                      outcome = repr(step.result) # Use result (optional field)
                  elif step.status == 'failed':
                      outcome = step.error_message or "Unknown error" # Use error_message (optional field)
                  elif step.status == 'skipped': outcome = "Skipped"
                  elif step.status == 'running': outcome = "Still running?"
                  else: outcome = "Not executed (Pending)" # Default status

                  # Sanitize and truncate outcome
                  outcome_summary = str(outcome).replace("|", "\\|").replace("\n", " ")
                  max_len = 100
                  if len(outcome_summary) > max_len: outcome_summary = outcome_summary[:max_len] + '...'

                  report_lines.append(f"| {step.id} | `{step.tool_name}` | {step_status} | {outcome_summary} |")
             report_lines.append("") # Add blank line after table
        elif plan:
             report_lines.append("_Plan existed but contained no steps._")
        else:
             report_lines.append("_No execution plan was available for this task._")


        # --- Final Result Details ---
        report_lines.append(f"\n## Final Result Details")
        if task.status == "completed":
            # Ensure result is treated as optional
            if task.result is None:
                 report_lines.append("_Task completed successfully, no specific result data recorded._")
            elif isinstance(task.result, (str, int, float, bool)):
                 report_lines.append(f"```\n{task.result}\n```")
            else: # Attempt to format dicts/lists nicely
                 try:
                      result_str = json.dumps(task.result, indent=2, ensure_ascii=False)
                      report_lines.append(f"```json\n{result_str}\n```")
                 except TypeError:
                      report_lines.append(f"```\n{repr(task.result)}\n```") # Fallback
        elif task.status == "failed":
             report_lines.append("_Task failed. See error message in header._")
        else:
             report_lines.append(f"_Task finished with status {task.status.upper()}._")


        report_content = "\n\n".join(report_lines) # Use double newline for better markdown spacing

        # --- Save Report to File (Optional) ---
        try:
             config = get_config_value('skills.reporting', {})
             if isinstance(config, dict): # Check if config is a dictionary
                 output_dir_str = config.get('output_dir', 'reports')
                 # Calculate project root relative to this file's location (src/skills/reporting/generator.py)
                 project_root = Path(__file__).resolve().parent.parent.parent.parent
                 output_dir = project_root / output_dir_str
                 output_dir.mkdir(parents=True, exist_ok=True)
                 # Use timezone-aware UTC time for filename consistency
                 ts = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')
                 # Sanitize task.id for filename if necessary
                 safe_task_id = "".join(c if c.isalnum() or c in ('-', '_') else '_' for c in task.id)
                 filename = f"report_{safe_task_id}_{ts}.md"
                 output_path = output_dir / filename

                 with open(output_path, "w", encoding="utf-8") as f:
                     f.write(report_content)
                 logger.info(f"Report saved to: {output_path}")
             else:
                 logger.warning("Reporting skill config is invalid or missing. Cannot save report to file.")

        except OSError as file_err: # Catch file system errors specifically
             logger.error(f"Failed to save report file: {file_err}", exc_info=True)
        except Exception as e: # Catch other potential errors
             logger.error(f"An unexpected error occurred during report saving: {e}", exc_info=True)


        return report_content # Always return the content string

    except Exception as e:
        logger.error(f"[{skill_name.upper()}] Failed unexpectedly during report content generation: {e}", exc_info=True)
        # Raise SkillError to signal failure in report generation itself
        raise SkillError(skill_name=skill_name, message=f"Error generating report content: {e}", original_exception=e) from e